#include <iostream>
#include <queue>
using namespace std;

template<class T>
class Blockqueue
{
private:
    bool ISFULL()
    {
        return _blockqueue.size() == _cup;
    }
        
    bool ISEMPTY()
    {
        return _blockqueue.size() == 0;
    }
       
public:
    Blockqueue(int cup)
    :_cup(cup)
    {
        pthread_mutex_init(&mutex,nullptr);
        pthread_cond_init(&productor,nullptr);
        pthread_cond_init(&consumer,nullptr);
        productor_wait_num = 0;
        consumer_wait_num = 0;
    }
    void Enqueue(const T& data)
    {
        //加锁
        pthread_mutex_lock(&mutex);
        while(ISFULL())
        {
            //满了，不能进去生产，需要等消费者消费
            productor_wait_num++;
            pthread_cond_wait(&productor,&mutex);
            productor_wait_num--;
        }
        //不满,生产者生产
        _blockqueue.push(data);
        //通知消费者消费
        if(consumer_wait_num > 0)
            pthread_cond_signal(&consumer);
        //解锁
        pthread_mutex_unlock(&mutex);
        
    }
    void Pop(T* out)
    {
        //加锁
        pthread_mutex_lock(&mutex);
        while(ISEMPTY())
        {
            //空了，不能进去消费，需要等生产者生产
            consumer_wait_num++;
            pthread_cond_wait(&consumer,&mutex);
            consumer_wait_num--;
        }
        //不空，消费者消费
        *out = _blockqueue.front();
        _blockqueue.pop();
        //通知生产者生产
        if(productor_wait_num > 0)
            pthread_cond_signal(&productor);
        //解锁
        pthread_mutex_unlock(&mutex);
    }
    ~Blockqueue()
    {
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&productor);
        pthread_cond_destroy(&consumer);
    }
private:
    queue<T> _blockqueue;
    int _cup; //最多存放
    pthread_mutex_t mutex;
    pthread_cond_t productor;//专门给生产者的
    pthread_cond_t consumer;//专门给消费者的

    int productor_wait_num;
    int consumer_wait_num;

};